package org.luxor.commons.playwright.component;

import com.microsoft.playwright.Browser;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 浏览器连接管理器
 *
 * @author Mr.yan @date 2023/6/9
 */
public class BrowserConnectManager {
    /**
     * 所有连接(key=endpointUrl,value=顺序ID)
     */
    private final ConcurrentHashMap<String, Integer> fullCache = new ConcurrentHashMap();

    /**
     * 休眠连接(key=endpointUrl,value=回收时间戳)
     */
    private final ConcurrentHashMap<String, Long> inactiveCache = new ConcurrentHashMap();

    /**
     * 活跃连接(key=endpointUrl,value=browser.hashCode)
     */
    private final ConcurrentHashMap<String, Integer> activeCache = new ConcurrentHashMap();

    public BrowserConnectManager(List<String> endpointUrls) {
        for (int sortIndex = 0; sortIndex < endpointUrls.size(); sortIndex++) {
            fullCache.put(endpointUrls.get(sortIndex), sortIndex);
        }
        for (int index = endpointUrls.size() - 1; index > -1; index--) {
            inactiveCache.put(endpointUrls.get(index), System.nanoTime());
        }
    }

    /**
     * 活跃连接
     *
     * @param browser
     * @param endpointUrl
     */
    public synchronized void active(Browser browser, String endpointUrl) {
        activeCache.put(endpointUrl, browser.hashCode());
        inactiveCache.remove(endpointUrl);
    }

    /**
     * 回收连接
     *
     * @param browser
     */
    public synchronized void inactive(Browser browser) {
        String endpointUrl = null;
        for (Map.Entry<String, Integer> activeEntry : activeCache.entrySet()) {
            if (browser.hashCode() == activeEntry.getValue()) {
                endpointUrl = activeEntry.getKey();
            }
        }
        if (endpointUrl == null) {
            return;
        }
        inactiveCache.put(endpointUrl, System.nanoTime());
        activeCache.remove(endpointUrl);
    }

    /**
     * 获取休眠的连接
     *
     * @return java.lang.String
     */
    public synchronized String getEndpointUrl() {
        return inactiveCache.entrySet().stream().sorted(
                (o1, o2) -> o1.getValue() > o2.getValue() ? -1 : o1.getValue() < o2.getValue() ? 1 : 0
        ).findFirst().get().getKey();
    }

    public synchronized int activeCount() {
        return activeCache.size();
    }

    public synchronized int inactiveCount() {
        return inactiveCache.size();
    }

    public synchronized int fullCount() {
        return fullCache.size();
    }

}
